/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Implementation of class CEnergyData
 * \author Antti Maula <antti.maula@tkk.fi>
 * \author Marek Matusiak
 *
 * $Id: EnergyData.cpp,v 1.5 2009-05-13 07:18:16 amaula Exp $
 *
 */
#include "EnergyData.hpp"
#include "owndebug.h"

//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
using namespace MaCI::Energy;
//*****************************************************************************
OWNDEBUG_INITIALIZE_MODULENUMBER(); // Initialize module print capability
//*****************************************************************************

CEnergyData::CEnergyData()
  : iTimestampPtr(NULL),
    iCommandPtr(NULL),
    iEnergyEventPtr(NULL),
    iEnergyLevelPtr(NULL),
    iMaxEnergyLevelPtr(NULL),
    iConsumptionPtr(NULL)
{
  SetLastElementType(KTypeUnknown);
}
//*****************************************************************************

CEnergyData::~CEnergyData()
{
  // Do any cleanups here.
}
//*****************************************************************************

CEnergyData::CEnergyData(const CEnergyData &aData)
  :  iTimestampPtr(NULL),
     iCommandPtr(NULL),
     iEnergyEventPtr(NULL),
     iEnergyLevelPtr(NULL),
     iMaxEnergyLevelPtr(NULL),
     iConsumptionPtr(NULL)
{
  // Call assignment operator.
  *this = aData;
}
//*****************************************************************************

CEnergyData &CEnergyData::operator=(const CEnergyData &aData)
{
  // Reset
  Reset();

  // Create an internal BinBag instance
  if (CreateInternalBinBag(aData.iBinBagContainer) == false) {
    dPrint(4,"WARNING: Failed to create internal binbag for object %p from object %p",
           this, &aData);
  }
  
  // Do the decode on the buffer; it sets pointers and ... stuff :)
  if (DecodeFrom(NULL) == false) {
    dPrint(4,"Warning: Failed to Decode CEnergyData even though assignment operator used?");
  }
  
  return *this; 
}
//*****************************************************************************

bool CEnergyData::DecodeFrom(gim::binbag::CBinBag *aBinBag)
{
  bool result = true;
  const gim::binbag::TBinBlob *b = NULL;
  int previous_type = -1;
  
  // Store pointer and test it for NullNess. only overwrite if the
  // argument was non-NULL.
  if (aBinBag != NULL) 
    SetBinBagContainerPtr(aBinBag);

  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary()) && result ) {
      switch(b->type) {

      case KTypeTimestamp:
	if (iTimestampPtr == NULL && 
            b->size == sizeof(Common::TTimestamp)) {
	  iTimestampPtr = reinterpret_cast<const Common::TTimestamp *>(b->data);

	} else result = false;
	break;

      case KTypeCommand: {
        if (iCommandPtr == NULL && 
            b->size == sizeof(TCommand)) {
          iCommandPtr = reinterpret_cast<const TCommand *>(b->data); 

        } else result = false;
        break;
      }

      case KTypeEnergyEvent: {
        if (iEnergyEventPtr == NULL && 
            b->size == sizeof(TEnergyEvent)) {
          iEnergyEventPtr = reinterpret_cast<const TEnergyEvent *>(b->data); 

        } else result = false;
        break;
      }
      
      case KTypeEnergyLevel: {
        if (iEnergyLevelPtr == NULL && 
            b->size == sizeof(float)) {
          iEnergyLevelPtr = reinterpret_cast<const float *>(b->data); 

        } else result = false;
        break;
      }
      case KTypeMaxEnergyLevel: {
        if (iMaxEnergyLevelPtr == NULL && 
            b->size == sizeof(float)) {
          iMaxEnergyLevelPtr = reinterpret_cast<const float *>(b->data); 

        } else result = false;
        break;
      }
      case KTypeConsumption: {
        if (iConsumptionPtr == NULL && 
            b->size == sizeof(float)) {
          iConsumptionPtr = reinterpret_cast<const float *>(b->data); 

        } else result = false;
        break;
      }

      default:
	// Unknown Type in BinBag. Do nothing.
	dPrint(10,"Unknown type %u, ignoring.", b->type);
        break;
      }
      
      // Store previous type
      previous_type = b->type;
    }
  } else result = false;

  // Store the result
  SetReadOnlyContainer(result);

  return result;
}
//*****************************************************************************

void CEnergyData::Reset()
{
  // Call base class reset.
  CMaCIData::Reset();

  // Clean out. (Same values as in default constructor)
  iTimestampPtr = NULL;
  iCommandPtr = NULL;
  iEnergyEventPtr = NULL;
  iEnergyLevelPtr = NULL;
  iMaxEnergyLevelPtr = NULL;
  iConsumptionPtr = NULL;
  SetLastElementType(KTypeUnknown);
}
//*****************************************************************************

void CEnergyData::Print(const int l) const
{
  const gim::binbag::TBinBlob *b = NULL;
  // Parse
  if (iBinBagContainer && iBinBagContainer->Rewind()) {
    while( (b = iBinBagContainer->GetNextBinary())) {
      switch(b->type) {
      case KTypeTimestamp: {
	const Common::TTimestamp *ts = 
          reinterpret_cast<const Common::TTimestamp *>(b->data);
	dPrint(l,"TTimestamp: s=%d, us=%d", 
	       ts->timestamp_s,
	       ts->timestamp_us);
	break;
      }
        
      case KTypeCommand: {
	const TCommand *ts = 
          reinterpret_cast<const TCommand *>(b->data);
	dPrint(l,"TCommand: cmd=%d, data=%d", 
	       ts->cmd, ts->data);
	break;
      }
	
      case KTypeEnergyEvent: {
	const TEnergyEvent *ae = 
          reinterpret_cast<const TEnergyEvent *>(b->data);
	dPrint(l,"TEnergyEvent: type=%d, energyLevel=%.3f, energyMax=%.3f, consumption=%.3f",
               ae->type,
               ae->energyLevel,
	       ae->energyMax,
	       ae->consumption);
	break;
      }
      
      case KTypeEnergyLevel: {
        const float *el =
        reinterpret_cast<const float *>(b->data);
	dPrint(l,"Energy Level: %.3f",
               el);
	break;        
      }

      case KTypeMaxEnergyLevel: {
        const float *el =
        reinterpret_cast<const float *>(b->data);
	dPrint(l,"Max Energy Level: %.3f",
               el);
	break;        
      }
      
      case KTypeConsumption: {
        const float *el =
        reinterpret_cast<const float *>(b->data);
	dPrint(l,"Power consumption: %.3f",
               el);
	break;        
      }

      default:
	// Unknown Type in BinBag. Do nothing.
	dPrint(10,"Unknown type %u, ignoring.", b->type);
        break;
      }
    }
  }
}
//*****************************************************************************

bool CEnergyData::SetTimestamp(const Common::TTimestamp &aStamp)
{
  bool result = false;
  if (!IsReadOnlyContainer() && iTimestampPtr == NULL) {
    ADDELEMENT(Common::TTimestamp, KTypeTimestamp, iTimestampPtr, aStamp);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool CEnergyData::SetCommand(const TCommand &aCmd)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iCommandPtr == NULL) {
    ADDELEMENT(TCommand, KTypeCommand, iCommandPtr, aCmd);
    result = true;
  }
  return result;
}
//*****************************************************************************

bool CEnergyData::SetEnergyEvent(const TEnergyEvent &aEvent)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iEnergyEventPtr == NULL) {
    ADDELEMENT(TEnergyEvent, KTypeEnergyEvent, iEnergyEventPtr, aEvent);
    result = true;
  }
  return result;
}
//*****************************************************************************
bool CEnergyData::SetEnergyLevel(const float level)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iEnergyLevelPtr == NULL) {
    ADDELEMENT(float, KTypeEnergyLevel, iEnergyLevelPtr, level);
    result = true;
  }
  return result;
}
//*****************************************************************************
bool CEnergyData::SetMaxEnergyLevel(const float level)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iMaxEnergyLevelPtr == NULL) {
    ADDELEMENT(float, KTypeMaxEnergyLevel, iMaxEnergyLevelPtr, level);
    result = true;
  }
  return result;
}
//*****************************************************************************
bool CEnergyData::SetConsumption(const float consumption)
{  
  bool result = false;
  if (!IsReadOnlyContainer() && iConsumptionPtr == NULL) {
    ADDELEMENT(float, KTypeConsumption, iConsumptionPtr, consumption);
    result = true;
  }
  return result;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

const MaCI::Common::TTimestamp *CEnergyData::GetTimestamp(void) const
{
  return iTimestampPtr;
}
//*****************************************************************************

const TCommand *CEnergyData::GetCommand(void) const
{
  return iCommandPtr;
}
//*****************************************************************************

const TEnergyEvent *CEnergyData::GetEnergyEvent(void) const
{
  return iEnergyEventPtr;
}
//*****************************************************************************
const float *CEnergyData::GetEnergyLevel(void) const
{
  return iEnergyLevelPtr;
}
//*****************************************************************************
const float *CEnergyData::GetMaxEnergyLevel(void) const
{
  return iMaxEnergyLevelPtr;
}
//*****************************************************************************
const float *CEnergyData::GetConsumption(void) const
{
  return iConsumptionPtr;
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

#ifdef COMPILE_ENERGYDATA_STANDALONE_MAIN
#include <string>

int main(void)
{
  using namespace MaCI::Energy;
  gim::binbag::CBinBag bb;
  CEnergyData A;
  CEnergyData B;
  bool r;

  printf("Carry out Encoding/Decoding test.\n");

  printf("Encoding...\n");
  // Do Encoding 
  A.EncodeTo(&bb);
  
  printf("Encode: Timestamp(1,2) ... ");
  r = A.SetTimestamp(MaCI::Common::TTimestamp(1, 2));
  assert(r == true);
  printf("OK.\n");
  
  printf("Encode: TEnergyEvent(KEventTypeEnergyData,79.1,360000,11.2) ... ");
  r = A.SetEnergyEvent(MaCI::Energy::TEnergyEvent(KEventTypeEnergyData,79.1,360000,11.2));
  assert(r == true);
  printf("OK.\n");
  
  printf("Encode: Energy level 80");
  r = A.SetEnergyLevel(80.0);
  assert(r == true);
  printf("OK.\n");
  
  printf("Encode: MaxEnergy level 200000.0");
  r = A.SetMaxEnergyLevel(200000.0);
  assert(r == true);
  printf("OK.\n");
  
  printf("Encode: Power consumption 15.0");
  r = A.SetConsumption(15.0);
  assert(r == true);
  printf("OK.\n");
  

  /**
   * \todo Add test sections for TEnergyEvent and TCommand
   */
  //////////////////////////////////////////////////////////
  printf("Decoding...\n");
  // Do Decoding
  B.DecodeFrom(&bb);
  printf("Decode: GetTimestamp() = (%d, %d) ... ", 
	 B.GetTimestamp()->timestamp_s, 
	 B.GetTimestamp()->timestamp_us);
  assert(B.GetTimestamp()->timestamp_s == 1);
  assert(B.GetTimestamp()->timestamp_us == 2);
  printf("Assertions OK.\n\n");
  
  printf("Decode: GetEnergyEvent() = (%d, %f, %f, %f) ... ", 
	 B.GetEnergyEvent()->type, 
	 B.GetEnergyEvent()->energyLevel,
	 B.GetEnergyEvent()->energyMax,
	 B.GetEnergyEvent()->consumption);
  assert(B.GetEnergyEvent()->type == KEventTypeEnergyData);
  printf("Assertions OK.\n\n");


  printf("Decode: GetEnergyLevel() = (%f) ... \n", 
	 *B.GetEnergyLevel());
  printf("Decode: GetMaxEnergyLevel() = (%f) ... \n", 
	 *B.GetMaxEnergyLevel());
  printf("Decode: GetConsumption() = (%f) ... \n", 
	 *B.GetConsumption());
  /**
   * \todo Add test sections for TEnergyEvent and TCommand
   */

  printf("Test complete.\n");
  

}
#endif
//*****************************************************************************
//*****************************************************************************
